package edu.asu.cse360.dao;

import edu.asu.cse360.model.Idenfiable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;

import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

public class GenericJpaDao<T, PK extends Serializable> implements DataAccessObject<T, PK>{

    @PersistenceContext(unitName="cse360-model")
    private EntityManager entityManager;

    private Class<T> clazz;
    
    public GenericJpaDao(Class<T> clazz){
        this.clazz = clazz;
    }

    @Override
    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    @Override
    public void delete(T object) {
        Integer id = ((Idenfiable)object).getId();
        T attachedObject = read((PK)id);
        getEntityManager().remove(attachedObject);
    }

    @Override
    public T read(PK id) {
        return getEntityManager().find(clazz, id);
    }

    @Override
    public void update(T entity) {
        getEntityManager().merge(entity);
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    @Override
    public List<T> findList(String findQuery){
        return findList(findQuery, null);
    }

    @Override
    public T findSingleResult(String findQuery){
        return findSingleResult(findQuery, null);
    }

    @Override
    public List<T> findList(String findQueryName,Map<String, Object> params){
        List<T> results = new ArrayList<T>();
        Query findQuery = buildQuery(findQueryName, params);
        try{
            results = findQuery.getResultList();
        }catch(NoResultException nre){
        }
        return results;
    }

    @Override
    public T findSingleResult(String findQueryName, Map<String, Object> params){
        T result = null;
        Query findQuery = buildQuery(findQueryName, params);
        try{
            result = (T) findQuery.getSingleResult();
        }catch(NoResultException nre){
        }
        return result;
    }

    public Class<T> getTargetClass(){
        return clazz;
    }

    private Query buildQuery(String queryName, Map<String, Object> params) {
        Query query = entityManager.createNamedQuery(queryName);
        setParams(query, params);
        return query;
    }

    private void setParams(Query query, Map<String, Object> params) {
       if(params == null)return;
       for(String key : params.keySet()){
           Object value = params.get(key);
           query.setParameter(key, value);
       }
    }


}
